#这一部分用来加载Module下各模块

module Aio::Module
	require "find"
	require "pathname"

	class Loader

	Reg_klass_filter = /class (.*)[\s]+<[\s]+Aio::Module/
	Reg_ruby_file = /.rb$/

	attr_accessor :module_manager

		def initialize(module_manager)
			@module_manager = module_manager
		end
			
		# 分析各个文件夹目录
		# 目录格式 ~/aio/lib/modules/cisco/show_version.rb
		# 目录格式 ~/aio/lib/modules/cmd/cisco/show_version.rb
		# 目录格式包括了 cmd, input, output
		# cmd 放置各个命令模块
    # input 放置各种输入方式的模块
		# output 放置各种输出方式的模块
		def each_module_reference_name(path, opts={})
			::Dir.foreach(path) do |entry|
				if entry.downcase == "." or entry.downcase == ".."
					next
				end

				full_entry_path = ::File.join(path, entry)
				module_type = entry
				
				# 第一层目录结构，判断是否为cmd, input, output 的模块类型
				unless ::File.directory?(full_entry_path) and
										module_manager.module_type_enable?(module_type)
					next
				end

				# module_type = "cmd"
				# full_entry_path = "~/aio/lib/modules/cmd"

				full_entry_pathname = Pathname.new(full_entry_path)

				Find.find(full_entry_path) do |entry_descendant_path|
					if File.directory?(entry_descendant_path)
						next
					end

					# 判断是不是.rb 结尾，而不是 .rb.swp 结尾
					unless vaild_ruby_file?(entry_descendant_path)
						next
					end

					# entry_descendant_path 为ruby文件的完整绝对路径
					entry_descendant_pathname = Pathname.new(entry_descendant_path)

					# 获得 modules 的二级目录名称, cmd/cisco 中的cisco 
					# 或者 input/style 中的style
					base, _i = entry_descendant_pathname.split
					_i, module_layer_2 = base.split
					module_layer_2 = module_layer_2.to_s

					# 查询是否有效并且取得模块的类名
					module_klass_name = get_module_klass_name(entry_descendant_pathname)
					if module_klass_name.empty?
						next
					end

					# 获得参考名
					relative_entry_descendant_pathname = entry_descendant_pathname.relative_path_from(full_entry_pathname)
					_i, relative_entry_descendant_pathname = relative_entry_descendant_pathname.split
					relative_entry_descendant_path = relative_entry_descendant_pathname.to_s
					module_reference_name = module_reference_name_from_path(relative_entry_descendant_path)

					module_reference_name = [module_type, module_layer_2, module_reference_name].join("/")
					yield entry_descendant_path, module_type, module_layer_2, module_reference_name, module_klass_name
				end

			end
		end

		# 取模块的类名，以便以后调用
		def get_module_klass_name(full_path)
			fo = File.open(full_path)
			fo.each_line do |l|
				l = Aio::Base::Toolkit::String.safe(l)
				klass_name = Reg_klass_filter.match(l)
				if klass_name == nil
					next
				end
				klass_name = klass_name[1].strip
				return klass_name
			end
			return ""
		end

		def module_reference_name_from_path(path)
			path.gsub(Reg_ruby_file, '')
		end

		# 是否是有效的Ruby文件
		def vaild_ruby_file?(path)
			if Reg_ruby_file.match(path)
				return true
			end
			return false
		end

		# 全局加载模块
		def load_modules(path, opts={})
			count_by_module_type = {}

			each_module_reference_name(path, opts={}) do |full_module_path, module_type, module_layer_2, module_reference_name, module_klass_name|
				load_module(full_module_path, 
										module_type,
										module_layer_2,
										module_reference_name,
										module_klass_name,
										{
						#					:recalcuate_by_device_type => recalculate_by_device_type,
											:count_by_module_type => count_by_module_type,
										}
				)
											
			end
			module_manager.notify({
				:count_by_module_type => count_by_module_type,
			})
		end
			
		# 真正加载处
		# 并将模块全部实例化
		def load_module(full_module_path, module_type,module_layer_2, module_reference_name, module_klass_name, opts={})

			begin
				require "#{full_module_path}"
				module_klass = ::Object::const_get(module_klass_name).new
			rescue Exception
				puts "[-]	Can not load module: #{full_module_path}"
				#puts caller
				return
			end
			@module_manager.add_module(full_module_path, module_type, module_layer_2, module_reference_name, module_klass)

			# 计数
			# count_by_module_type = {"cmd" => { "cisco" => 2 }, "input" => { "style" => 1 } }
			count_by_module_type = opts[:count_by_module_type]
			if count_by_module_type
				if !count_by_module_type[module_type]
					count_by_module_type[module_type] = {}
				end

				count_by_module_type[module_type][module_layer_2] ||= 0
				count_by_module_type[module_type][module_layer_2] += 1
			end
		end

    # 获取modules的路径
    def self.modules_path
      local_path = Pathname.new(File.dirname(__FILE__)).realpath
      return File.join(local_path, "..", "..", "modules")
    end

    # 获取modules的路径
    def modules_path
      self.class.modules_path
    end

	end	#class
end		#module
		
